package com.ciei.dpagm.util;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * url请求工具类
 * @author laj
 *
 */
public class UrlUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(UrlUtil.class);

    /** 
     * 向指定URL发送GET方法的请求 
     *  
     * @param url 
     *            发送请求的URL 
     * @param param 
     *            请求参数，请求参数应该是 name1=value1&name2=value2 的形式。 
     * @return URL 所代表远程资源的响应结果 
     */  
    public static String sendGet(String url, String param) {  
        String result = "";  
        BufferedReader in = null;  
        try {  
            String urlNameString = url + "?" + param;  
            URL realUrl = new URL(urlNameString);  
            // 打开和URL之间的连接  
            URLConnection connection = realUrl.openConnection();  
            // 设置通用的请求属性  
            connection.setRequestProperty("accept", "*/*");  
            connection.setRequestProperty("connection", "Keep-Alive");  
            connection.setRequestProperty("user-agent",  
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");  
            // 建立实际的连接  
            connection.connect();  
            // 获取所有响应头字段  
            Map<String, List<String>> map = connection.getHeaderFields();  
            // 遍历所有的响应头字段  
            for (String key : map.keySet()) {  
                System.out.println(key + "--->" + map.get(key));  
            }  
            // 定义 BufferedReader输入流来读取URL的响应  
            in = new BufferedReader(new InputStreamReader(  
                    connection.getInputStream(), "UTF-8"));  
            String line;  
            while ((line = in.readLine()) != null) {  
                result += line;  
            }  
        } catch (Exception e) {  
            System.out.println("发送GET请求出现异常！" + e);  
            e.printStackTrace();  
        }  
        // 使用finally块来关闭输入流  
        finally {  
            try {  
                if (in != null) {  
                    in.close();  
                }  
            } catch (Exception e2) {  
                e2.printStackTrace();  
            }  
        }  
        return result;  
    }  
   
    /**  
     * 向指定 URL 发送POST方法的请求  
     *   
     * @param url  
     *            发送请求的 URL  
     * @param param  
     *            请求参数，请求参数应该是 name1=value1&name2=value2 的形式。  
     * @return 所代表远程资源的响应结果  
     */  
    public static String sendPost(String url, String param) {  
        PrintWriter out = null;  
        BufferedReader in = null;  
        String result = "";  
        try {  
            URL realUrl = new URL(url);  
            // 打开和URL之间的连接  
            URLConnection conn = realUrl.openConnection();  
            // 设置通用的请求属性  
            conn.setRequestProperty("accept", "*/*");  
            conn.setRequestProperty("connection", "Keep-Alive");  
            conn.setRequestProperty("user-agent",  
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");  
            // 发送POST请求必须设置如下两行  
            conn.setDoOutput(true);  
            conn.setDoInput(true);  
            // 获取URLConnection对象对应的输出流  
            out = new PrintWriter(conn.getOutputStream());  
            // 发送请求参数  
            out.print(param);  
            // flush输出流的缓冲  
            out.flush();  
            // 定义BufferedReader输入流来读取URL的响应  
            in = new BufferedReader(  
                    new InputStreamReader(conn.getInputStream(), "UTF-8"));  
            String line;  
            while ((line = in.readLine()) != null) {  
                result += line;  
            }  
        } catch (Exception e) {  
            System.out.println("发送 POST 请求出现异常！"+e);  
            e.printStackTrace();  
        }  
        //使用finally块来关闭输出流、输入流  
        finally{  
            try{  
                if(out!=null){  
                    out.close();  
                }  
                if(in!=null){  
                    in.close();  
                }  
            }  
            catch(IOException ex){  
                ex.printStackTrace();  
            }  
        }  
        return result;  
    }

    public static String getRealIpAddress(HttpServletRequest request){
        // 获取请求主机IP地址,如果通过代理进来，则透过防火墙获取真实IP地址

        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } else if (ip.length() > 15) {
            String[] ips = ip.split(",");
            for (int index = 0; index < ips.length; index++) {
                String strIp = (String) ips[index];
                if (!("unknown".equalsIgnoreCase(strIp))) {
                    ip = strIp;
                    break;
                }
            }
        }
        return ip;
    }

    /**
     * 使用HttpClients，向指定 URL 发送httpGet方法的请求
     *
     * @param url
     * 			发送请求的 URL(带参数)
     * @return  所代表远程资源的响应结果
     */
    public static String httpClientSendGet(String url) {
        InputStream is = null;
        BufferedReader bf = null;
        String result = null;
        //发起请求
        CloseableHttpClient client = HttpClients.createDefault();
        RequestConfig config = null;
        //没有代理，使用默认值
//		config = RequestConfig.custom().build();
        config = RequestConfig.custom().setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000)
                .setSocketTimeout(5000).build();
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(config);

        try {
            HttpResponse response = client.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if(statusCode == HttpStatus.SC_OK){
                HttpEntity entity = response.getEntity();
                if(entity != null) {
                    is = entity.getContent();
                    //解析字节流
                    bf = new BufferedReader(new InputStreamReader(is, "utf-8"));
                    StringBuilder sb=new StringBuilder();
                    String strRead=null;
                    while ((strRead=bf.readLine())!=null) {
                        sb.append(strRead+"\r\n");
                    }
//					JSONObject jsonObject = JSONObject.parseObject(sb.toString());
                    result = sb.toString();
                }
            }else {
                httpGet.abort();
                System.out.println("httpClientSendGet Error, status code :" + statusCode);
            }
        } catch (Exception e) {
            System.out.println("请求URL："+url);
            System.out.println("发送 HttpGet 请求出现异常！"+e);
//            e.printStackTrace();
        } finally{
            try{
                if(bf!=null){
                    bf.close();
                }
                if(is!=null){
                    is.close();
                }
                if(client!=null) {
                    //http关闭
                    client.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 使用HttpClients，向指定 URL 发送httpPost方法的请求
     * (用于key-value格式的参数)
     * @param url
     * 			发送请求的 URL
     * @param params
     * 			key-value格式请求参数
     * @return  所代表远程资源的响应结果
     */
    public static String httpClientSendPost(String url, Map<String,Object> params){
        InputStream is = null;
        BufferedReader bf = null;
        String result = null;

        // 定义HttpClient
        //HttpClient client = new DefaultHttpClient();
//		CloseableHttpClient client = HttpClients.createDefault();//请求https时，如果证书过期会报错
        CloseableHttpClient client = createSSLInsecureClient();//信任所有证书

        try {

            // 实例化HTTP方法
            HttpPost httpPost = new HttpPost();
            httpPost.setURI(new URI(url));
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            //设置参数
            List<NameValuePair> nvps = new ArrayList<NameValuePair>();
            for (Iterator<String> iter = params.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                String value = String.valueOf(params.get(name));
                nvps.add(new BasicNameValuePair(name, value));

//    			System.out.println(name +"-"+value);
            }
            httpPost.setEntity(new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8));

            HttpResponse response = client.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if(statusCode == HttpStatus.SC_OK){	//请求成功
                HttpEntity entity = response.getEntity();
                if(entity != null) {
                    is = entity.getContent();
                    //解析字节流
                    bf = new BufferedReader(new InputStreamReader(is,"utf-8"));
                    StringBuffer sb = new StringBuffer("");
                    String line = "";
                    String NL = System.getProperty("line.separator");
                    while ((line = bf.readLine()) != null) {
                        sb.append(line + NL);
                    }

                    result = sb.toString();
                }
            }
            else{
                httpPost.abort();
                System.out.println("httpClientSendPost Error, status code :" + statusCode);
                return null;
            }
        }
        catch(Exception e){
            System.out.println("请求URL："+url);
            System.out.println("发送 HttpPost 请求出现异常！"+e);
            e.printStackTrace();
        }
        finally {
            try{
                if(bf!=null){
                    bf.close();
                }
                if(is!=null){
                    is.close();
                }
                if(client!=null) {
                    //http关闭
                    client.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }

        }
        return result;
    }

    /***
     * 使用HttpClients，向指定 URL 发送httpPost方法的请求
     * (发送json数据)
     * @param url
     * 			发送请求的 URL
     * @param json
     * 			发送的json数据
     * @return  HttpEntity
     */
    public static String httpClientSendPost(String url, JSONObject json){
        if (json == null) {
            return "httpClientSendPost Error: json is null";
        }
        CloseableHttpClient httpclient = HttpClients.createDefault();
        RequestConfig config = null;
        //没有代理，使用默认值
        config = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).build();


        String result = null;
        try {
            // 实例化HTTP方法
            HttpPost httpPost = new HttpPost(url);
            httpPost.setConfig(config);
            StringEntity stringEntity = new StringEntity(json.toString(),"UTF-8");
//			stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");//发送json数据需要设置contentType
            httpPost.setEntity(stringEntity);
            HttpResponse httpResponse = httpclient.execute(httpPost);
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            if(statusCode == HttpStatus.SC_OK){	//请求成功
                HttpEntity entity = httpResponse.getEntity();
                if(entity != null) {
                    result = EntityUtils.toString(entity);
                }
            }else{
                httpPost.abort();
                result = "httpClientSendPost Error, status code :" + statusCode;
                LOGGER.warn(result);
            }
        } catch(Exception e){
            LOGGER.warn("HttpPost请求URL："+url);
            e.printStackTrace();
        } finally {
            try{
                if(httpclient!=null) {
                    //http关闭
                    httpclient.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }

    /**
     * https请求信任所有证书（避免证书过期导致请求出错）
     * @return
     */
    public static CloseableHttpClient createSSLInsecureClient() {
        try {
            SSLContext sslContext = new SSLContextBuilder()
                    .loadTrustMaterial(null, new TrustStrategy() {
                        //信任所有
                        @Override
                        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                            return true;
                        }
                    }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslContext);
            return HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return  HttpClients.createDefault();
    }

    /**
     * 检测目标主机是否能联通
     * @param host 主机名或IP
     * @param port 端口号
     * @return  true表示目标可联通，false表示目标不可联通
     */
    public static boolean isHostConnectable(String host, int port) {
        Socket socket = new Socket();
        InetSocketAddress inetSocketAddress = new InetSocketAddress(host, port);
        try {
            socket.connect(inetSocketAddress);
        } catch (IOException e) {
            //e.printStackTrace();
            return false;
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
}
